package io.itit.ecp.admin.provide.action.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.itit.ecp.admin.provide.action.req.SceneFloorQueryReq;
import io.itit.ecp.admin.provide.action.req.SceneFloorReq;
import io.itit.ecp.admin.provide.action.resp.SceneFloorResp;
import io.itit.ecp.admin.provide.renderer.SceneFloorRenderer;
import io.itit.ecp.admin.server.entity.SceneEdificeEntity;
import io.itit.ecp.admin.server.entity.SceneFloorEntity;
import io.itit.ecp.admin.server.entity.SceneProjectEntity;
import io.itit.ecp.admin.server.entity.SceneRoomEntity;
import io.itit.ecp.admin.server.service.ISceneEdificeService;
import io.itit.ecp.admin.server.service.ISceneFloorService;
import io.itit.ecp.admin.server.service.ISceneProjectService;
import io.itit.ecp.admin.server.service.ISceneRoomService;
import io.itit.grass.common.provide.action.req.BaseBatchIdReq;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.*;
import io.itit.grass.common.server.entity.BaseEntity;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.parse.ExcelParseManage;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * @Author：Roy
 * @Description：楼层控制类
 * @Date：Create by 2023-11-23 09:55:22
 */
@Api(tags = "楼层管理")
@RestController
@RequestMapping("/ecp-admin/sceneFloor")
public class SceneFloorController {

    @Resource
    private ISceneFloorService sceneFloorService;

    @Resource
    private ISceneProjectService sceneProjectService;

    @Resource
    private ISceneEdificeService sceneEdificeService;

    @Resource
    private ISceneRoomService sceneRoomService;

    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("ecp-admin:sceneFloor:search")
    public ResultResp<IPage<SceneFloorResp>> queryPage(@RequestBody @Validated(IQueryPage.class) SceneFloorQueryReq req) {
        Page<SceneFloorEntity> page = sceneFloorService.page(PageUtils.getPage(req, SceneFloorEntity.class), buildQW(req));
        List<String> floorIds = page.getRecords().stream().map(BaseEntity::getId).collect(Collectors.toList());
        IPage<SceneFloorResp> result = ConvertUtils.convert(page, SceneFloorResp.class);
        if (CollectionUtils.isNotEmpty(floorIds)) {
            Map<String, Object> map = sceneRoomService.listMaps(new QueryWrapper<SceneRoomEntity>()
                            .select("scene_floor_id,count(id) count")
                            .in("scene_floor_id", floorIds)
                            .groupBy("scene_floor_id")).stream()
                    .collect(Collectors.toMap(item -> String.valueOf(item.get("scene_floor_id")), m -> m.getOrDefault("count", 0L)));
            for (SceneFloorResp item : result.getRecords()) {
                item.setRoomNum(map.get(item.getId()) == null ? 0 : Integer.parseInt(map.get(item.getId()).toString()));
            }
        }
        return ResultResp.success(result);
    }

    @ApiOperation("列表查询")
    @PostMapping("queryList")
    @RequiresPermissions("ecp-admin:sceneFloor:search")
    public ResultResp<List<SceneFloorResp>> queryList(@RequestBody SceneFloorQueryReq req) {
        List<SceneFloorEntity> list = sceneFloorService.list(buildQW(req));
        return ResultResp.success(ConvertUtils.convert(list, SceneFloorResp.class));
    }

    @ApiOperation("树查询")
    @PostMapping("queryTree")
    public ResultResp<List<Map<String, Object>>> queryTree(@RequestBody SceneFloorQueryReq req) {
        List<SceneProjectEntity> projectList = sceneProjectService.list(new QueryWrapper<>());
        List<SceneEdificeEntity> edificeEntities = sceneEdificeService.list(new QueryWrapper<>());
        List<SceneFloorEntity> floorList = sceneFloorService.list(buildQW(req));
        List<Map<String, Object>> result = new ArrayList<>(projectList.size());
        Map<String, List<SceneEdificeEntity>> projectMap = edificeEntities.stream()
                .collect(Collectors.groupingBy(SceneEdificeEntity::getSceneProjectId));

        Map<String, List<SceneFloorEntity>> floorMap = floorList.stream()
                .collect(Collectors.groupingBy(SceneFloorEntity::getSceneEdificeId));

        for (SceneProjectEntity item : projectList) {
            Map<String, Object> m = new HashMap<>();
            m.put("id", item.getId());
            m.put("label", item.getProjectName());
            m.put("type", 1);
            m.put("children", projectMap.getOrDefault(item.getId(), Collections.emptyList()).stream().map(edifice -> {
                Map<String, Object> edificeMap = new HashMap<>();
                edificeMap.put("id", edifice.getId());
                edificeMap.put("label", edifice.getEdificeName());
                edificeMap.put("type", 2);
                edificeMap.put("children", floorMap.getOrDefault(edifice.getId(), Collections.emptyList()).stream().map(floor -> {
                    Map<String, Object> fMap = new HashMap<>();
                    fMap.put("id", floor.getId());
                    fMap.put("label", floor.getFloorName());
                    fMap.put("type", 3);
                    return fMap;
                }).collect(Collectors.toList()));
                return edificeMap;
            }).collect(Collectors.toList()));
            result.add(m);
        }
        return ResultResp.success(result);
    }

    @ApiOperation("获取建筑面积最大与最小值")
    @PostMapping("getarearange")
    public ResultResp<Map<String, BigDecimal>> getAreaRange(@RequestBody SceneRoomEntity roomEntity) {
        SceneFloorEntity floorEntity = sceneFloorService.getById(roomEntity.getSceneFloorId());
        BigDecimal minValue = BigDecimal.ZERO;
        BigDecimal maxValue = BigDecimal.valueOf(Integer.MAX_VALUE);
        if (Objects.nonNull(floorEntity)) {
            List<SceneRoomEntity> roomEntities = sceneRoomService.lambdaQuery()
                    .select(SceneRoomEntity::getRoomArea)
                    .eq(SceneRoomEntity::getSceneFloorId, floorEntity.getId())
                    .ne(StringUtils.isNotEmpty(roomEntity.getId()), SceneRoomEntity::getId, roomEntity.getId())
                    .list();
            BigDecimal useArea = roomEntities.stream().map(SceneRoomEntity::getRoomArea).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            maxValue = floorEntity.getFloorArea().subtract(useArea);
        }
        Map<String, BigDecimal> result = new HashMap<>();
        result.put("minValue", minValue);
        result.put("maxValue", maxValue);
        return ResultResp.success(result);
    }

    @ApiOperation("详情")
    @PostMapping("detail")
    public ResultResp<SceneFloorResp> detail(@RequestBody @Validated(IRequired.class) BaseIdReq req) {
        return ResultResp.success(ConvertUtils.copy(sceneFloorService.getById(req.getId()), SceneFloorResp.class));
    }

    /**
     * 组装查询条件
     */
    private static LambdaQueryWrapper<SceneFloorEntity> buildQW(SceneFloorQueryReq req) {
        return Wrappers.<SceneFloorEntity>lambdaQuery()
                .eq(StringUtils.isNotEmpty(req.getSceneEdificeId()), SceneFloorEntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(req.getFloorNum() != null, SceneFloorEntity::getFloorNum, req.getFloorNum())
                .eq(StringUtils.isNotEmpty(req.getFloorName()), SceneFloorEntity::getFloorName, req.getFloorName())
                .eq(StringUtils.isNotEmpty(req.getDeptId()), SceneFloorEntity::getDeptId, req.getDeptId())
                .in(CollectionUtils.isNotEmpty(req.getIds()), SceneFloorEntity::getId, req.getIds())
                .last(StringUtils.isNotEmpty(req.getSortColumn()), PageUtils.lastOrderBy(req))
                .orderByDesc(StringUtils.isEmpty(req.getSortColumn()), SceneFloorEntity::getCreateTm);
    }

    @ApiOperation("新增")
    @PostMapping("add")
    @RequiresPermissions("ecp-admin:sceneFloor:add")
    public ResultResp<Boolean> add(@RequestBody @Validated({IAdd.class}) SceneFloorReq req) {
        return ResultResp.success(sceneFloorService.save(ConvertUtils.convertIgnoreId(req, SceneFloorEntity.class)));
    }

    @ApiOperation("编辑")
    @PostMapping("update")
    @RequiresPermissions("ecp-admin:sceneFloor:update")
    public ResultResp<Boolean> update(@RequestBody @Validated({IUpdate.class}) SceneFloorReq req) {
        if (Objects.nonNull(req.getFloorArea())) {
            SceneFloorEntity sceneFloor = sceneFloorService.getById(req.getId());
            if (Objects.isNull(sceneFloor)) {
                return ResultResp.fail("楼层不存在");
            }
            SceneEdificeEntity sceneEdifice = sceneEdificeService.getById(sceneFloor.getSceneEdificeId());
            if (Objects.nonNull(sceneEdifice) && sceneEdifice.getFloorArea().compareTo(req.getFloorArea()) < 0) {
                return ResultResp.fail("建筑面积不可大于所属楼栋的建筑面积");
            }
            BigDecimal totalRoomArea = sceneRoomService.list(new LambdaQueryWrapper<SceneRoomEntity>().eq(SceneRoomEntity::getSceneFloorId, req.getId())).stream()
                    .map(SceneRoomEntity::getRoomArea).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            if (req.getFloorArea().compareTo(totalRoomArea) < 0) {
                ResultResp.fail("建筑面积不可小于绑定该楼层所有空间总建筑面积");
            }
        }
        return ResultResp.success(sceneFloorService.updateById(ConvertUtils.copy(req, SceneFloorEntity.class)));
    }

    @ApiOperation("删除(根据Id删)")
    @PostMapping("deleteById")
    @RequiresPermissions("ecp-admin:sceneFloor:deleteById")
    public ResultResp<Boolean> deleteById(@RequestBody @Validated({IRequired.class}) BaseIdReq req) {
        return ResultResp.success(sceneFloorService.removeFloors(Collections.singletonList(req.getId())));
    }

    @ApiOperation("批量删除")
    @PostMapping("batchDelete")
    @RequiresPermissions("ecp-admin:sceneFloor:batchDelete")
    public ResultResp<Boolean> batchDelete(@RequestBody @Validated({IRequired.class}) BaseBatchIdReq req) {
        return ResultResp.success(sceneFloorService.removeFloors(req.getIds()));
    }

    @ApiOperation("导入")
    @PostMapping("upload")
    @RequiresPermissions("ecp-admin:sceneFloor:upload")
    public ResultResp<Integer> upload(@RequestParam("file") MultipartFile file, Boolean ignoreError) {
        return ResultResp.success(ExcelParseManage.i().process(SceneFloorRenderer.ENTITY_NAME, file, ignoreError));
    }

    @ApiOperation("导出")
    @PostMapping("export")
    @RequiresPermissions("ecp-admin:sceneFloor:export")
    public void export(@RequestBody @Validated(IExport.class) SceneFloorQueryReq req, HttpServletResponse response) {
        ExcelXSSFUtil.export("SceneFloorExport", JsonUtil.toJson(sceneFloorService.list(buildQW(req))), response);
    }
}
